package cn.tips.dmp.common.upload;

import cn.hutool.core.util.ObjectUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import cn.tips.dmp.supports.result.ApiResultDTO;
import cn.tips.dmp.supports.result.ApiResultGenerator;
import cn.tips.dmp.supports.status.ComConstant;
import cn.tips.dmp.common.upload.po.AttachFile;
import cn.tips.dmp.common.upload.service.AttachFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;

/**
 * @program: tips_back_end
 * @description: 上传文件公共类
 * @author: kzl
 * @create: 2020-06-29 09:50
 **/
@RestController
@RequestMapping("/api/upload")
@Slf4j
public class UploadFileController {

    @Autowired
    private UploadConfigProperties uploadConfigProperties;

    @Autowired
    private AliyunUploadProperties aliyunUploadProperties;

    @Autowired
    private NfsDiskProperties nfsDiskProperties;

    @Autowired
    private AttachFileService attachFileService;

    @Autowired
    private  AliyunUploadFileHandler aliyunUploadFileHandler;

    @Autowired
    JPAQueryFactory jpaQueryFactory;



    @PostMapping("/save")
    public ApiResultDTO save(@RequestParam("file") MultipartFile file,String type, long relationId) {
        ApiResultDTO apiResultDto;
        AttachFile attachFile= attachFileService.getOneByRelationId(relationId);
        try {
            // 获取文件原始名称
            String originalFileName = file.getOriginalFilename();
            // 创建临时文件
            File tempFile = File.createTempFile("temp", originalFileName.substring(originalFileName.lastIndexOf(".")));
//            String fileName = qiNiuUploadFileHandler.save(tempFile, originalFileName);
//            File f = new File(file.getOriginalFilename());

            //获取存储地址
            String fileUrl = "";
            if(uploadConfigProperties.getType() == ComConstant.UploadType.ALIYUN){
//             将上传文件转为临时文件
                file.transferTo(tempFile);
                fileUrl = aliyunUploadFileHandler.uploadObject2OSS(tempFile, 1);
            }else if(uploadConfigProperties.getType() == ComConstant.UploadType.NFSDISK){
                File fileP = new File(nfsDiskProperties.getFileSaveLocation());
                if (!fileP.isDirectory()) {
                    //递归生成文件夹
                    fileP.mkdirs();
                }
                String filename = UUID.randomUUID().toString() + originalFileName.substring(originalFileName.lastIndexOf("."));
                file.transferTo(new File(fileP, filename));
                fileUrl = nfsDiskProperties.getFileShowLocation() + relationId + "/" + filename;
            }
            if(attachFile == null){
                attachFile = new AttachFile();
                attachFile.setRelationId(relationId);
            }
            attachFile.setName(originalFileName);
            attachFile.setType(type);
            attachFile.setPath(fileUrl);
            attachFileService.save(attachFile);
            // 退出时删除临时文件
            tempFile.deleteOnExit();
            apiResultDto = ApiResultGenerator.create("0", "上传文件成功!",attachFile);
        } catch (Exception e) {
            log.error("上传文件失败:", e);
            apiResultDto = ApiResultGenerator.create("-1", "上传文件失败!" + e.getMessage());
        }
        return apiResultDto;
    }

    /**
     * 保存成果附件
     * @param file
     * @param type
     * @return
     */
    @PostMapping("/saveFruit")
    public ApiResultDTO saveFruit(@RequestParam("file") MultipartFile file, String type, int businessType) {
        ApiResultDTO apiResultDto;
        AttachFile attachFile= new AttachFile();
        try {
            // 获取文件原始名称
            String originalFileName = file.getOriginalFilename();
            // 获取文件后缀
            String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
            if(!suffix.contains("pdf、docx、doc、xlsx、xls、ppt、pptx、jpg、jpeg、png")){
                return ApiResultGenerator.create("-1", "上传文件失败, 文件格式仅支持[pdf、docx、doc、xlsx、xls、ppt、pptx、jpg、jpeg、png]!");
            }

            // 创建临时文件
            File tempFile = File.createTempFile("temp", originalFileName.substring(originalFileName.lastIndexOf(".")));
//            String fileName = qiNiuUploadFileHandler.save(tempFile, originalFileName);
//            File f = new File(file.getOriginalFilename());
            //获取存储地址
            String fileUrl = "";
            if(uploadConfigProperties.getType() == ComConstant.UploadType.ALIYUN){
//              将上传文件转为临时文件
                file.transferTo(tempFile);
                fileUrl = aliyunUploadFileHandler.uploadObject2OSS(tempFile, 2);
            }else if(uploadConfigProperties.getType() == ComConstant.UploadType.NFSDISK){
                File fileP = new File(nfsDiskProperties.getFileSaveLocation());
                if (!fileP.isDirectory()) {
                    //递归生成文件夹
                    fileP.mkdirs();
                }
                String filename = UUID.randomUUID().toString() + originalFileName.substring(originalFileName.lastIndexOf("."));
                file.transferTo(new File(fileP, filename));
                fileUrl = nfsDiskProperties.getFileSaveLocation() + filename;
            }
            attachFile.setName(originalFileName);
            attachFile.setType(type);
            attachFile.setBusinessType(businessType);
            attachFile.setPath(fileUrl);
            // 退出时删除临时文件
            tempFile.deleteOnExit();

            attachFile = attachFileService.save(attachFile);
            apiResultDto = ApiResultGenerator.create("0", "上传文件成功!",attachFile);
        } catch (Exception e) {
            log.error("上传文件失败:", e);
            apiResultDto = ApiResultGenerator.create("-1", "上传文件失败!" + e.getMessage());
        }
        return apiResultDto;
    }


//    @PostMapping("/saveFiles")
//    public ApiResultDTO save(@RequestParam("files") MultipartFile[] files,String type) {
//        ApiResultDTO apiResultDto;
//        List<AttachFile> attachFiles= new ArrayList<>();
//        try {
//            for(MultipartFile file: files) {
//                AttachFile attachFile= new AttachFile();
//                // 获取文件原始名称
//                String originalFileName = file.getOriginalFilename();
//                // 创建临时文件
//                File tempFile = File.createTempFile("temp", originalFileName.substring(originalFileName.lastIndexOf(".")));
//                // 将上传文件转为临时文件
//                file.transferTo(tempFile);
//                String fileName = qiNiuUploadFileHandler.save(tempFile, originalFileName);
//                attachFile.setName(originalFileName);
//                attachFile.setType(type);
//                attachFile.setPath(qiNiuUploadProperties.getUrl()+ "/"+fileName);
//                attachFiles.add(attachFile);
//                // 退出时删除临时文件
//                tempFile.deleteOnExit();
//            }
//            apiResultDto = ApiResultGenerator.create("0", "上传文件成功!", attachFiles);
//        } catch (Exception e) {
//            log.error("上传文件失败:", e);
//            apiResultDto = ApiResultGenerator.create("-1", "上传文件失败!" + e.getMessage());
//        }
//        return apiResultDto;
//    }

    @PostMapping("/delete")
    public ApiResultDTO save(@RequestBody AttachFile dto) {
        ApiResultDTO apiResultDto;
        List<AttachFile> attachFiles= new ArrayList<>();
        try {
            attachFileService.delete(dto.getId());
            apiResultDto = ApiResultGenerator.create("0", "文件删除成功!", attachFiles);
        } catch (Exception e) {
            log.error("上传文件失败:", e);
            apiResultDto = ApiResultGenerator.create("-1", "文件删除成功!" + e.getMessage());
        }
        return apiResultDto;
    }


    @PostMapping("/saveOssFileData")
    public ApiResultDTO saveOssFileData(@RequestBody AttachFile attachFile) {

        ApiResultDTO apiResultDto;
        try {
            attachFile = attachFileService.save(attachFile);
            apiResultDto = ApiResultGenerator.create("0", "上传文件成功!", attachFile);
        } catch (Exception e) {
            log.error("上传文件失败:", e);
            e.printStackTrace();
            apiResultDto = ApiResultGenerator.create("-1", "上传文件失败!" + e.getMessage());
        }
        return apiResultDto;
    }


    @GetMapping("/previewFile/{relationId}/{imgName}")
    public void previewFile(@PathVariable("relationId") long relationId, @PathVariable("imgName") String imgName, HttpServletResponse response) {
        try {
            AttachFile attachFile = attachFileService.getOneByRelationId(relationId);
            if(!ObjectUtil.isEmpty(attachFile)){
                OutputStream os = response.getOutputStream();
                File file = new File(nfsDiskProperties.getFileSaveLocation() + imgName);
                if (file.exists()) {
                    response.setContentType("application/octet-stream");
                    //处理文件名为中文的情况
                    response.setHeader("Content-Disposition", "attach;filename=" + new String(attachFile.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));

                    os.write(Files.readAllBytes(file.toPath()));
                } else {
                    writeToResponse("There is no such file", response);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            writeToResponse(e.getMessage(), response);
        }
    }

    /**
     * 将文本信息返回到response中，主要用于没有明显返回数据的请求，例如上传'下载等，可用于提示失败的信息。
     *
     * @param message
     * @param response
     */
    public static void writeToResponse(String message, HttpServletResponse response) {
        try (ServletOutputStream out = response.getOutputStream();
            OutputStreamWriter ow = new OutputStreamWriter(out, Charset.forName("UTF-8"));) {
            ow.write(message);
            ow.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @PostMapping("/downloadFileData")
    public void downloadFileData(@RequestBody AttachFile attachFile, HttpServletResponse response) {
        attachFile = attachFileService.getAttachFileById(attachFile.getId());
        if(!this.validateDownload(attachFile)){
            // 用户没有权限，发送错误信息
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            writeToResponse("对不起，您暂无权限下载!", response);
        }else{
            OutputStream outputStream = null;
            BufferedInputStream bis = null;
            OSS ossClient = null;
            try {

                String fileName = attachFile.getPath().substring(attachFile.getPath().lastIndexOf("/") + 1);

                outputStream = new BufferedOutputStream(response.getOutputStream());

                response.reset();
                response.setContentType("application/octet-stream");
                //处理文件名为中文的情况
                response.setHeader("Content-Disposition", "attach;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));

                if(uploadConfigProperties.getType() == ComConstant.UploadType.ALIYUN){
                    ossClient = new OSSClientBuilder().build(aliyunUploadProperties.getEndpoint(), aliyunUploadProperties.getAccessKey(), aliyunUploadProperties.getSecertKey());
                    // 填写Object完整路径，例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
                    String objectName = aliyunUploadProperties.getFruitFolderName() + "/" + fileName;
                    OSSObject ossObject = ossClient.getObject(aliyunUploadProperties.getBucket(), objectName);
                    // 读取文件内容。
                    bis = new BufferedInputStream(ossObject.getObjectContent(), 512);

                    //*处理oss文件流传输*
                    int number;
                    byte[] buffer = new byte[512];
                    while ((number = bis.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, number);
                    }
                    ossObject.close();
                }else if(uploadConfigProperties.getType() == ComConstant.UploadType.NFSDISK){
                    // 读到流中
//                InputStream inStream = new FileInputStream(nfsDiskProperties.getFileSaveLocation() + "/" + fileName);
                    InputStream inStream = new FileInputStream(attachFile.getPath());
                    int number;
                    byte[] buffer = new byte[512];
                    while ((number = inStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, number);
                    }
                    inStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (ossClient != null) {
                    ossClient.shutdown();
                }
                if (outputStream != null) {
                    try {
                        outputStream.flush();
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }


    /**
     * 鉴权 下载是否有权限
     */
    public boolean validateDownload(AttachFile attachFile){
//        Set<Long> relationIdList = new HashSet<>();
//        switch (attachFile.getBusinessType()){
//            case ComConstant.UploadBusinessType.FRUIT :
//                Set<Long> fruitIdList = new HashSet<>();
//                //查询当前账号下的机构成果relationId列表
//                if(!ObjectUtil.isEmpty(OrgAccountHelper.getOrgIdList())){
//                    QFruitPO qFruitPO = QFruitPO.fruitPO;
//                    QFruitOrgRelPo qFruitOrgRelPo = QFruitOrgRelPo.fruitOrgRelPo;
//                    // 成果
//                    List<Long> orgFruitIdList = jpaQueryFactory.selectDistinct(qFruitPO.id)
//                            .from(qFruitOrgRelPo)
//                            .leftJoin(qFruitPO).on(qFruitOrgRelPo.fruitId.eq(qFruitPO.id))
//                            .where(qFruitOrgRelPo.orgId.in(OrgAccountHelper.getOrgIdList()))
//                            .fetch();
//                    if(!ObjectUtil.isEmpty(orgFruitIdList)){
//                        fruitIdList.addAll(orgFruitIdList);
//                    }
//                }
//                //查询当前账号下的成果relationId列表
//                QFruitAuthorPO qFruitAuthorPO = QFruitAuthorPO.fruitAuthorPO;
//                //查询作者关联的作者成果信息
//                List<Long> authorFruitIdList = jpaQueryFactory.select(qFruitAuthorPO.fruitId).from(qFruitAuthorPO)
//                        .where(qFruitAuthorPO.orgUserId.eq(OrgAccountHelper.getUserId()).and(qFruitAuthorPO.isDel.isFalse())).fetch();
//
//                if(!ObjectUtil.isEmpty(authorFruitIdList)){
//                    fruitIdList.addAll(authorFruitIdList);
//                }
//
//                if(!ObjectUtil.isEmpty(fruitIdList)){
//                    relationIdList.addAll(fruitIdList);
//                    // 报送信息
//                    QFruitSubPO qFruitSubPO = QFruitSubPO.fruitSubPO;
//                    List<Long> orgSubIdList = jpaQueryFactory.selectDistinct(qFruitSubPO.id)
//                            .from(qFruitSubPO)
//                            .where(qFruitSubPO.fruitId.in(fruitIdList))
//                            .fetch();
//                    relationIdList.addAll(orgSubIdList);
//                    // 批示信息
//                    QFruitLeaderPO qFruitLeaderPO = QFruitLeaderPO.fruitLeaderPO;
//                    List<Long> orgPsIdList = jpaQueryFactory.selectDistinct(qFruitLeaderPO.id)
//                            .from(qFruitLeaderPO)
//                            .where(qFruitLeaderPO.fruitId.in(fruitIdList))
//                            .fetch();
//                    relationIdList.addAll(orgPsIdList);
//                }
//                if(!ObjectUtil.isEmpty(relationIdList) && relationIdList.contains(attachFile.getRelationId())){
//                    return true;
//                }
//
//                break;
//            default:
//                return false;
//        }
        return false;
    }
}
